<template>
  <div class="chart-bar-trace-root" v-loading="vLoading">
    <div class="trace-app-pie" ref="ChartPieTraceAppRef"></div>
    <div class="trace-bar" ref="ChartBarTraceRef" />
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, nextTick } from "vue";
import { spansApi } from "@/api/tracker";
import { timestampToDatetime } from "@/assets/utils/util";
import { isNotNull, isNull } from "@/assets/utils/obj";
// echarts
import * as echartTheme from '@/assets/styles/xz/echartTheme';
import * as appTheme from '@/views/guardcat/app/AppTheme';
import * as echarts from 'echarts/core';
import * as trackerTheme from './TrackerTheme';
import { BarChart, PieChart } from 'echarts/charts';
import { CanvasRenderer } from 'echarts/renderers';
import { TitleComponent, TooltipComponent, GridComponent, LegendComponent } from 'echarts/components';
echarts.use([TitleComponent, TooltipComponent, GridComponent, LegendComponent, BarChart, PieChart, CanvasRenderer]);

const props = defineProps({
  traceId: { type: String, default: '' }
})

const vLoading = ref(true)
const ChartBarTraceRef = ref<any>(null);
let chartBarTrace: any;
let traceName: any;
let startDt: any;// 代表开始的位置
let lengthDt: any;// 代表用时, 即bar的长度
let spanList: any;
let animation: boolean = true;

const getSpansApi = () => {
  animation = true;
  spansApi({ traceId: props.traceId }).then((resp: any) => {
    spanList = resp.data.spans;
    chartPieData = resp.data.appAggs;
    computeChartBarData(true);
    renderChartPie()
  })
}

/**
 * 计算柱状图的样式.
 * @param isAnimation 是否显示动画, 在初次加载时显示, 根据应用高亮时不显示
 * @param focusAppName 关注的应用名称
 */
const computeChartBarData = (isAnimation: boolean, focusAppName?: string): void => {
  animation = isAnimation;
  traceName = [];
  startDt = [];
  lengthDt = [];

  // 根节点，既 spanParentId == null 的节点
  const rootSpan: any = spanList.filter((span: any) => span.spanParentId === 'ROOT_SPAN')[0];
  // 链路的结束时间
  const maxEnd = Math.max(...spanList.map((item: any) => Number(item.spanEnd)));
  // 链路的开始时间
  let minStart = Number(rootSpan.spanStart);
  // 总用时
  let allInterval = maxEnd - minStart;

  // 开始循环全部节点
  spanList.forEach((span: any) => {

    const isFocus = isNotNull(focusAppName) && span.appName !== focusAppName;

    let spanStartNumber = Number(span.spanStart);
    // --------------------------- 判断柱状图的样式 ---------------------------
    // 根据 spanType 设置柱状图的样式
    let style = trackerTheme.barStyle(span.spanType);
    if (isFocus) {
      style = trackerTheme.barStyle('IGNORE');
    }
    if (isNull(style)) {
      style = trackerTheme.barStyle('OTHER');
    }

    // 设置 spanName, 作为 y 轴类目
    traceName.push(span.spanName);

    // 根节点的开始位置为0，其他节点的开始位置为：开始时间 - 根节点开始时间
    if (span.spanParentId === 'ROOT_SPAN') {
      startDt.push(0);
    } else {
      startDt.push(spanStartNumber - minStart);
    }

    // bar 的长度, 可能是0
    let value = span.spanParentId === 'ROOT_SPAN' ? maxEnd - minStart : span.spanInterval;
    // 如果 bar 的长度是0, 为了能在图表中体现出来, 则设置为1
    if (!isFocus && value === 0) {
      style = trackerTheme.barStyle('PLACEHOLDER');
    }
    // 决定 bar 
    let positionLeft = (spanStartNumber - minStart) <= allInterval / 2;
    // 设置
    lengthDt.push({
      value: value == 0 ? 1 : value,
      appName: span.appName,
      spanType: span.spanType,
      spanStart: timestampToDatetime(spanStartNumber),
      spanEnd: timestampToDatetime(Number(span.spanEnd)),
      spanInterval: span.spanInterval,
      records: span.records,
      position: positionLeft ? 'insideLeft' : 'insideRight',
      label: {
        color: isNull(style.labelColor) ? trackerTheme.labelColor() : style.labelColor,
        position: positionLeft ? 'insideLeft' : 'insideRight',
        rich: {
          intervalStyle: { backgroundColor: style.labelRichIntervalColor },
        }
      },
      itemStyle: {
        color: style.color,
        borderColor: style.borderColor,
        borderWidth: style.borderWidth,
        borderType: 'dashed'
      }
    });
    renderChartBar();
  });
}

// 
const renderChartBar = () => {
  chartBarTrace.setOption({
    title: { top: 10, right: 10, text: '链路追踪图示', textStyle: echartTheme.title().textStyle },
    tooltip: {
      ...echartTheme.tooltip(), ...{
        // enterable: true,
        // alwaysShowContent: true,
        axisPointer: { type: 'shadow' },
        position: function (pos: any, params: any, el: any, elRect: any, size: any) {
          let obj: any = { top: 10 };
          obj[['left', 'right'][+(pos[0] < size.viewSize[0] / 2)]] = 30;
          return obj;
        },
        formatter: function (params: any) {
          let records = params[1].data.records;
          let div = '<div style="font-size:12px;max-width:400px;">'
            + '<div style="font-size: 13px;font-weight: bold;border-bottom: 2px solid #636363;margin-bottom: 10px;white-space: break-spaces;word-break: break-all;">'
            + params[1].name
            + '</div>'
            + '服务: ' + params[1].data.appName + '<br/>'
            + '类型: ' + params[1].data.spanType + '<br/>'
            + '用时: ' + (params[1].data.spanInterval == 0 ? '<1' : params[1].data.spanInterval) + 'ms<br/>'
            + '开始时间: ' + params[1].data.spanStart + '<br/>'
            + '结束时间: ' + params[1].data.spanEnd + '<br/>';
          for (let objKey in records) {
            div += '<div style="word-break:break-all;white-space: pre-wrap;width: 100%">' + objKey + ': ' + records[objKey] + '<div/>';
          }
          return div + '</div>';
        }
      }
    },
    grid: { top: 5, left: 10, right: 10, bottom: 10, containLabel: true },
    xAxis: {
      type: 'value',
      animation: false,
      splitLine: { lineStyle: { color: [echartTheme.common().axisLineColor] } }
    },
    yAxis: {
      type: 'category',
      offset: 1,
      animation: animation,
      data: traceName,
      axisLine: { onZero: false, },
      axisLabel: { show: false },
      splitLine: { show: false }
    },
    series: [
      {
        type: 'bar',
        name: '1',
        stack: 'Total',
        barMaxWidth: 44,
        barCategoryGap: '10%',
        animation: false,
        itemStyle: {
          borderColor: 'transparent',
          color: 'transparent'
        },
        emphasis: {
          itemStyle: {
            borderColor: 'transparent',
            color: 'transparent'
          }
        },
        data: startDt
      },
      {
        type: 'bar',
        name: '2',
        stack: 'Total',
        animation: animation,
        itemStyle: {
          borderRadius: 10,
        },
        label: {
          show: true,
          fontFamily: echartTheme.common().fontFamily,
          fontSize: 13,
          // lineHeight: 13,
          distance: 5,// 距离元素的距离
          formatter: (params: any) => {
            let interval = "{intervalStyle|" + (params.data.spanInterval == 0 ? '<1' : params.data.spanInterval) + "ms}";
            // position: positionLeft ? 'insideLeft' : 'insideRight',
            if (params.data.position === 'insideLeft') {
              return interval + " " + params.name;
            }
            return params.name + " " + interval;
          },
          // https://echarts.apache.org/zh/tutorial.html#%E5%AF%8C%E6%96%87%E6%9C%AC%E6%A0%87%E7%AD%BE
          rich: {
            intervalStyle: {
              padding: [3, 5, 1, 5],
              fontSize: 10,
              backgroundColor: trackerTheme.labelIntervalColor(),
              borderRadius: 10
            }
          }
        },
        data: lengthDt
      }
    ]
  })
}

// ----------------------------------------< 饼图 >----------------------------------------
const ChartPieTraceAppRef = ref();
let chartPieTraceApp: any;
let chartPieData: any;

const renderChartPie = () => {
  chartPieTraceApp.setOption(
    {
      title: { top: 5, right: 5, text: '追踪应用占比', textStyle: echartTheme.title().textStyle },
      legend: { ...echartTheme.legend(), ...{ orient: 'vertical', itemStyle: { opacity: 1 } } },
      tooltip: { ...echartTheme.tooltip(), ...{ trigger: 'item' } },
      series: [
        {
          type: 'pie',
          radius: ['30%', '70%'],
          avoidLabelOverlap: false,
          // radius: '70%',
          // minAngle: 10,
          // animation: false,
          label: { show: false },
          itemStyle: {
            borderRadius: 10,
            borderWidth: 2,
            borderColor: echartTheme.common().backgroundColor,
            color: (param: any) => {
              return appTheme.style(param.data.appName).color;
            }
          },
          data: chartPieData,
          // emphasis: {
          // itemStyle: {
          // shadowBlur: 10,
          // shadowOffsetX: 0,
          // shadowColor: 'rgba(0, 0, 0, 0.5)'
          // }
          // }
        }
      ]
    })
}

const reload = () => {
  nextTick(() => {
    getSpansApi();
  })
}

const windowResize = () => {
  chartBarTrace.resize();
}

const init = () => {
  chartPieTraceApp = echarts.init(ChartPieTraceAppRef.value);
  chartBarTrace = echarts.init(ChartBarTraceRef.value);
  // 鼠标移入图形的事件
  chartPieTraceApp.on('mouseover', function (event: any) {
    computeChartBarData(false, event.data.appName);
  })
  chartPieTraceApp.on('globalout', function (event: any) {
    // computeChartBarData(false);
  })
}

onMounted(() => {
  init();
  windowResize();
})

defineExpose({
  reload, windowResize
})
</script>

<style scoped lang="scss">
.chart-bar-trace-root {
  @include box(100%, 100%);
  @include flex(row, flex-start, center);

  .trace-app-pie {
    @include box(400px, 100%);
  }

  .trace-bar {
    @include box(calc(100% - 400px), 100%);
  }
}
</style>